#include <string.h>
#include "card_nxp520.h"

void SPI_Card_Init(void)
{
	Device_Enable(VHW_SPI_CARD);
}

/**
  * @brief  SPI3 读写一个字节
  * @note   
  *         
  * @param  TxData:要写入的字节
  * @return 返回值:读取到的数据
  */
uint8_t SPI_Card_ReadWriteByte(uint8_t txData)
{
	uint8_t rxData = 0;
	
    Device_Write(VHW_SPI_CARD, &txData, 1, (uint32_t)&rxData);
	return rxData;
}

/*
一、MF1卡(S50/S70卡)的技术参数
　　1、工作频率：13.56MHz
　　2、存储容量：
　　　　S50卡：1024字节，16个扇区，每个扇区4个块
　　　　S70卡：4096字节，40个扇区，前32个扇区每扇区4个块，后8个扇区每扇区16个块
　　3、协议标准：ISO 14443 A
　　4、擦写寿命：大于100,000次
　　5、数据保存时间：10年
　　6、应用范围：在一卡通领域等广泛应用


            0块数据  card1   card2   card3
卡号[0]     byte[0]  0x12    0xf5    0x42
卡号[1]     byte[1]  0x01    0xd2    0xdc
卡号[2]     byte[2]  0xf0    0x5d    0xc5
卡号[3]     byte[3]  0x43    0xbb    0xb6
卡号CRC     byte[4]  0xa0    0xc1    0xed
卡SIZE      byte[5]  0x08    0x08    0x08
卡片类型    byte[6]  0x04    0x04    0x04
            byte[7]  0x00    0x00    0x00
            byte[8]  0x69    0x23    0x62
            byte[9]  0x73    0x56    0x63
            byte[10] 0x73    0x83    0x64
            byte[11] 0x69    0x49    0x65
            byte[12] 0x35    0x04    0x66
            byte[13] 0x31    0x11    0x67
            byte[14] 0x34    0xff    0x68
            byte[15] 0x30    0xff    0x69
   */

uint16_t sWaitCmdLoopTimes; //等待命令ok loop

/*******************************************************************************
* Function Name  : Set_Waitcmd_Loop
* Description    : 设置等待命令发送接收循环次数
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void Set_Waitcmd_Loop(uint16_t times)
{
	sWaitCmdLoopTimes = times;
}

/*******************************************************************************
* Function Name  : set_waitcmd_loop
* Description    : 获取loop
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
uint16_t Get_Waitcmd_Loop(void)
{
	return sWaitCmdLoopTimes;
}

//读卡芯片端口配置
//NRST---PA8
//CS ----PA10
void Nxp520_Portinit(void)
{
	SPI_Card_Init();

	MF_CS_H;
	MF_NRST_H;
}

/////////////////////////////////////////////////////////////////////
//功    能：清RC522寄存器位
//参数说明：reg[IN]:寄存器地址
//          mask[IN]:清位值
/////////////////////////////////////////////////////////////////////
void ClearBitMask(unsigned char reg, unsigned char mask)
{
	char tmp = 0x0;
	tmp = Nxp520_Read_Reg(reg);
	Nxp520_Write_Reg(reg, tmp & ~mask); // clear bit mask
}
//////////////////////////////////////////////////////////////////////
//设置RC522的工作方式
//////////////////////////////////////////////////////////////////////
//int nxp520ConfigISOType(uint8_t type)
//{
//	if (type == 'A')
//	{
//  	ClearBitMask(Status2Reg,0x08);
//		Nxp520_Write_Reg(ModeReg,0x3D);
//		Nxp520_Write_Reg(RxSelReg,0x86);
//		Nxp520_Write_Reg(RFCfgReg,0x7F);
//		Nxp520_Write_Reg(TReloadRegL,30);
//		Nxp520_Write_Reg(TReloadRegH,0);
//		Nxp520_Write_Reg(TModeReg,0x8D);
//		Nxp520_Write_Reg(TPrescalerReg,0x3E);
//		System_DelayMs(10);
//		Nxp520_Antenna_On();
//	}else
//	{
//	   return MI_NOTAGERR;
//	}

//  return MI_OK;
//}

//SPI写数据
void spi_write_string(uint8_t cmd, uint8_t *pointer, uint16_t len)
{
	uint8_t i;

	MF_CS_L;

	SPI_Card_ReadWriteByte(cmd);
	for (i = 0; i < len; i++)
	{
		SPI_Card_ReadWriteByte(pointer[i]);
	}

	MF_CS_H;
}

//SPI读数据
void spi_read_string(uint8_t cmd, uint8_t *pointer, uint16_t len)
{
	uint8_t i;

	MF_CS_L;

	SPI_Card_ReadWriteByte(cmd);
	for (i = 0; i < len; i++)
	{
		pointer[i] = SPI_Card_ReadWriteByte(0x00);
	}

	MF_CS_H;
}

//NXP520 写寄存器
void Nxp520_Write_Reg(uint8_t addr, uint8_t date)
{
	addr = (addr << 1) & 0x7e; //写寄存器的时候，地址最高位为 0，最低位为0，1-6位取决于地址

	MF_CS_L;
	SPI_Card_ReadWriteByte(addr);
	SPI_Card_ReadWriteByte(date);
	MF_CS_H;
}
//NXP520 读寄存器
uint8_t Nxp520_Read_Reg(uint8_t addr)
{
	uint8_t ret;
	addr = ((addr << 1) & 0x7e) | 0x80; //读寄存器的时候，地址最高位为 1，最低位为0，1-6位取决于地址

	MF_CS_L;
	SPI_Card_ReadWriteByte(addr);
	ret = SPI_Card_ReadWriteByte(0);
	MF_CS_H;

	return ret;
}
/////////////////////////////////////////////////////////////////////
//功    能：置RC522寄存器位
//参数说明：reg[IN]:寄存器地址
//          mask[IN]:置位值
/////////////////////////////////////////////////////////////////////
void Set_Reg_Mask(unsigned char reg, unsigned char mask)
{
	char tmp = 0x0;
	tmp = Nxp520_Read_Reg(reg);
	Nxp520_Write_Reg(reg, tmp | mask);
}
/////////////////////////////////////////////////////////////////////
//功    能：清RC522寄存器位
//参数说明：reg[IN]:寄存器地址
//          mask[IN]:清位值
/////////////////////////////////////////////////////////////////////
void cls_reg_mask(unsigned char reg, unsigned char mask)
{
	char tmp = 0x0;
	tmp = Nxp520_Read_Reg(reg);
	Nxp520_Write_Reg(reg, tmp & ~mask);
}

signed char Nxp520_Reset(void)
{
	uint16_t i = 0;

	MF_NRST_H;
	OSAL_DelayUs(300); //不加延时可能会出现异常
	do
	{
		if (Nxp520_Read_Reg(0x04) == 0x14)
		{
			break;
		}
	} while (++i < 10000);

	Nxp520_Write_Reg(CommandReg, PCD_RESETPHASE);
	Nxp520_Write_Reg(ModeReg, 0x39);
	Nxp520_Write_Reg(GsNReg, 0xf8);			//27reg      -N-MOS  高4位决定开启数量
	Nxp520_Write_Reg(CWGsCfgReg, 0x3f);		//28reg  -P-MOS  低6位决定开启数量
	Nxp520_Write_Reg(RxThresholdReg, 0x97); /* 位解码器阈值设置 */
	Nxp520_Write_Reg(RFCfgReg, 0x58);		/* RxGain 38dB */
	Nxp520_Write_Reg(TxAutoReg, 0x40);		/* 强制100%ASK调制 */
	Nxp520_Write_Reg(CommandReg, PCD_IDLE);
	return MI_OK;
}

/**
  * @brief  读取卡片ID
  *           
  * @param  pId：卡片ID数据指针
  * @param  type：卡片类型代码
	*         0x4400 = Mifare_UltraLight
	*         0x0400 = Mifare_One(S50)
	*         0x0200 = Mifare_One(S70)
	*         0x0800 = Mifare_Pro(X)
	*         0x4403 = Mifare_DESFire
  *
  * @return 返回ID号长度，读取失败返回0
  */
uint8_t Nxp520_ReadCardId(uint8_t *pId, uint16_t *pType)
{
	uint8_t len = 0;

	if (Lowpower_Request(PICC_REQIDL, (uint8_t *)pType) == MI_OK) // 寻卡
	{
		len = UL_PcdAnticoll(pId); //获取卡号
	}
	return len;
}

//开启天线
void Nxp520_Antenna_On(void)
{
	unsigned char i;

	i = Nxp520_Read_Reg(TxControlReg);
	if (!(i & ANT_CONFIG))
	{
		Set_Reg_Mask(TxControlReg, ANT_CONFIG);
	}
}
//关闭天线
void Nxp520_Antenna_Off(void)
{
	cls_reg_mask(TxControlReg, ANT_CONFIG);
}
//与卡片通信
/////////////////////////////////////////////////////////////////////
//功    能：通过RC522和ISO14443卡通讯
//参数说明：Command[IN]:RC522命令字
//          pInData[IN]:通过RC522发送到卡片的数据
//          InLenByte[IN]:发送数据的字节长度
//          pOutData[OUT]:接收到的卡片返回数据
//          *pOutLenBit[OUT]:返回数据的位长度
//////////////////////////////////////////////////////////////////
uint8_t nxp520_communicate_card(unsigned char Command,
								unsigned char *pInData,
								unsigned char InLenByte,
								unsigned char *pOutData,
								unsigned int *pOutLenBit)
{
	signed char status = MI_ERR;
	unsigned char irqEn = 0x00;
	unsigned char waitFor = 0x00;
	unsigned char lastBits;
	unsigned char n;
	unsigned int i;

	switch (Command)
	{
	case PCD_AUTHENT:
	{
		irqEn = 0x12;
		waitFor = 0x10;
	}
	break;

	case PCD_TRANSCEIVE:
	{
		irqEn = 0x77;
		waitFor = 0x30;
	}
	break;
	default:
		break;
	}

	Nxp520_Write_Reg(ComIEnReg, irqEn | 0x80); //使能接受和发送中断请求
	cls_reg_mask(ComIrqReg, 0x80);			   //置ComIrqReg为0xff,
	Nxp520_Write_Reg(CommandReg, PCD_IDLE);	   //取消当前命令
	Set_Reg_Mask(FIFOLevelReg, 0x80);
	for (i = 0; i < InLenByte; i++)
	{
		Nxp520_Write_Reg(FIFODataReg, pInData[i]);
	}
	Nxp520_Write_Reg(CommandReg, Command); //开始发送
	if (Command == PCD_TRANSCEIVE)
	{
		Set_Reg_Mask(BitFramingReg, 0x80);
	} //

	i = 2000; //根据时钟频率调整，操作M1卡最大等待时间25ms
	do
	{
		n = Nxp520_Read_Reg(ComIrqReg);
		i--;
	} while ((i != 0) && !(n & 0x01) && !(n & waitFor));
	cls_reg_mask(BitFramingReg, 0x80); //发送结束

	if (i != 0) //发送完成
	{
		if (!(Nxp520_Read_Reg(ErrorReg) & 0x1B))
		{
			status = MI_OK;
			if (n & irqEn & 0x01)
			{
				status = MI_NOTAGERR;
			}

			if (Command == PCD_TRANSCEIVE)
			{
				n = Nxp520_Read_Reg(FIFOLevelReg);
				lastBits = Nxp520_Read_Reg(ControlReg) & 0x07;

				if (lastBits)
					*pOutLenBit = (n - 1) * 8 + lastBits;
				else
				{
					*pOutLenBit = n * 8;
				}

				if (n == 0)
					n = 1;

				if (n > MAXRLEN)
				{
					n = MAXRLEN;
				}
				for (i = 0; i < n; i++)
				{
					pOutData[i] = Nxp520_Read_Reg(FIFODataReg);
				}
			}
		}
		else
		{
			status = MI_ERR;
		}
	}

	Set_Reg_Mask(ControlReg, 0x80); // stop timer now
	Nxp520_Write_Reg(CommandReg, PCD_IDLE);

	return status;
}
//功    能：寻卡
//参数说明: req_code[IN]:寻卡方式
//                0x52 = 寻感应区内所有符合14443A标准的卡
//                0x26 = 寻未进入休眠状态的卡
//                pTagType[OUT]：卡片类型代码
//                0x4400 = Mifare_UltraLight
//                0x0400 = Mifare_One(S50)
//                0x0200 = Mifare_One(S70)
//                0x0800 = Mifare_Pro(X)
//                0x4403 = Mifare_DESFire
//返    回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////
signed char Nxp520_Request(unsigned char req_code, unsigned char *pTagType)
{
	volatile signed char status; //不加 volatile 可能会被优化 2012.007.05
	unsigned int unLen;
	unsigned char ucComMF522Buf[MAXRLEN];
	unsigned char *p = pTagType;

	cls_reg_mask(Status2Reg, 0x08);			//清除密文发送
	Nxp520_Write_Reg(BitFramingReg, 0x07);	//最后字节只传7位，请求命令是短帧！！！！
	Set_Reg_Mask(TxControlReg, ANT_CONFIG); //打开天线脚驱动

	ucComMF522Buf[0] = req_code; //寻天线为进入休眠状态的卡

	status = nxp520_communicate_card(PCD_TRANSCEIVE, ucComMF522Buf, 1, ucComMF522Buf, &unLen);

	if ((status == MI_OK) && (unLen == 0x10))
	{
		*p = ucComMF522Buf[0];
		*(p + 1) = ucComMF522Buf[1];
	}
	else
	{
		status = MI_ERR;
	}

	return status;
}

/////////////////////////////////////////////////////////////////////
//功    能：防冲撞
//参数说明: pSnr[OUT]:卡片序列号，4字节
//返    回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////
char Nxp520_Anticoll(unsigned char *pSnr)
{
	signed status;
	unsigned char i, snr_check = 0;
	unsigned int unLen;
	unsigned char ucComMF522Buf[MAXRLEN];
	cls_reg_mask(Status2Reg, 0x08); //清0，当验证密码成功时此位置1
	Nxp520_Write_Reg(BitFramingReg, 0x00);
	cls_reg_mask(CollReg, 0x80);
	ucComMF522Buf[0] = PICC_ANTICOLL1;
	ucComMF522Buf[1] = 0x20;
	status = nxp520_communicate_card(PCD_TRANSCEIVE, ucComMF522Buf, 2, ucComMF522Buf, &unLen);
	//FeedIWDG();
	if (status == MI_OK)
	{
		for (i = 0; i < 4; i++)
		{
			*(pSnr + i) = ucComMF522Buf[i];
			snr_check ^= ucComMF522Buf[i];
		}
		if (snr_check != ucComMF522Buf[i])
		{
			status = MI_ERR;
		}
	}
	Set_Reg_Mask(CollReg, 0x80);
	Nxp520_Antenna_Off();
	return status;
}

/////////////////////////////////////////////////////////////////////
//用MF522计算CRC16函数
/////////////////////////////////////////////////////////////////////
void nxp520_calulate_crc(unsigned char *pIndata, unsigned char len, unsigned char *pOutData)
{
	unsigned char i, n;

	cls_reg_mask(DivIrqReg, 0x04);
	Nxp520_Write_Reg(CommandReg, PCD_IDLE);
	Set_Reg_Mask(FIFOLevelReg, 0x80);
	for (i = 0; i < len; i++)
	{
		Nxp520_Write_Reg(FIFODataReg, *(pIndata + i));
	}
	Nxp520_Write_Reg(CommandReg, PCD_CALCCRC);
	i = 0xFF;
	do
	{
		n = Nxp520_Read_Reg(DivIrqReg);
		i--;
	} while ((i != 0) && !(n & 0x04));
	pOutData[0] = Nxp520_Read_Reg(CRCResultRegL);
	pOutData[1] = Nxp520_Read_Reg(CRCResultRegM);
}

/////////////////////////////////////////////////////////////////////
//功    能：选定卡片
//参数说明: pSnr[IN]:卡片序列号，4字节
//返    回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////
char Nxp520_Select(unsigned char *pSnr)
{
	signed char status;
	unsigned char i;
	unsigned int unLen;
	unsigned char ucComMF522Buf[MAXRLEN];

	ucComMF522Buf[0] = PICC_ANTICOLL1;
	ucComMF522Buf[1] = 0x70;
	ucComMF522Buf[6] = 0;
	for (i = 0; i < 4; i++)
	{
		ucComMF522Buf[i + 2] = *(pSnr + i);
		ucComMF522Buf[6] ^= *(pSnr + i);
	}
	nxp520_calulate_crc(ucComMF522Buf, 7, &ucComMF522Buf[7]);

	cls_reg_mask(Status2Reg, 0x08);

	status = nxp520_communicate_card(PCD_TRANSCEIVE, ucComMF522Buf, 9, ucComMF522Buf, &unLen);

	if ((status == MI_OK) && (unLen == 0x18))
	{
		status = MI_OK;
		pSnr[5] = ucComMF522Buf[0]; //卡容量2012.07.03
	}
	else
	{
		status = MI_ERR;
	}

	return status;
}

/////////////////////////////////////////////////////////////////////
//功    能：验证卡片密码
//参数说明: auth_mode[IN]: 密码验证模式
//                 0x60 = 验证A密钥
//                 0x61 = 验证B密钥
//          addr[IN]：块地址
//          pKey[IN]：密码
//          pSnr[IN]：卡片序列号，4字节
//返    回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////
char Nxp520_Auth_State(unsigned char auth_mode, unsigned char addr, unsigned char *pKey, unsigned char *pSnr)
{
	signed char status;
	unsigned int unLen;
	unsigned char i, ucComMF522Buf[MAXRLEN];

	ucComMF522Buf[0] = auth_mode;
	ucComMF522Buf[1] = addr;
	for (i = 0; i < 6; i++)
	{
		ucComMF522Buf[i + 2] = *(pKey + i);
	}
	for (i = 0; i < 6; i++)
	{
		ucComMF522Buf[i + 8] = *(pSnr + i);
	}

	status = nxp520_communicate_card(PCD_AUTHENT, ucComMF522Buf, 12, ucComMF522Buf, &unLen);
	if ((status != MI_OK) || (!(Nxp520_Read_Reg(Status2Reg) & 0x08)))
	{
		status = MI_ERR;
	}

	return status;
}

/////////////////////////////////////////////////////////////////////
//功    能：读取M1卡一块数据
//参数说明: addr[IN]：块地址
//          pData[OUT]：读出的数据，16字节
//返    回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////
char Nxp520_Read(unsigned char addr, unsigned char *pData)
{
	signed char status;
	unsigned int unLen;
	unsigned char i, ucComMF522Buf[MAXRLEN];

	ucComMF522Buf[0] = PICC_READ;
	ucComMF522Buf[1] = addr;
	nxp520_calulate_crc(ucComMF522Buf, 2, &ucComMF522Buf[2]);

	status = nxp520_communicate_card(PCD_TRANSCEIVE, ucComMF522Buf, 4, ucComMF522Buf, &unLen);
	if ((status == MI_OK) && (unLen == 0x90))
	//   {   memcpy(pData, ucComMF522Buf, 16);   }
	{
		for (i = 0; i < 16; i++)
		{
			*(pData + i) = ucComMF522Buf[i];
		}
	}
	else
	{
		status = MI_ERR;
	}

	return status;
}

/////////////////////////////////////////////////////////////////////
//功    能：写数据到M1卡一块
//参数说明: addr[IN]：块地址
//          pData[IN]：写入的数据，16字节
//返    回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////
char Nxp520_write(unsigned char addr, unsigned char *pData)
{
	signed char status;
	unsigned int unLen;
	unsigned char i, ucComMF522Buf[MAXRLEN];

	ucComMF522Buf[0] = PICC_WRITE;
	ucComMF522Buf[1] = addr;
	nxp520_calulate_crc(ucComMF522Buf, 2, &ucComMF522Buf[2]);

	status = nxp520_communicate_card(PCD_TRANSCEIVE, ucComMF522Buf, 4, ucComMF522Buf, &unLen);

	if ((status != MI_OK) || (unLen != 4) || ((ucComMF522Buf[0] & 0x0F) != 0x0A))
	{
		status = MI_ERR;
	}

	if (status == MI_OK)
	{
		//memcpy(ucComMF522Buf, pData, 16);
		for (i = 0; i < 16; i++)
		{
			ucComMF522Buf[i] = *(pData + i);
		}
		nxp520_calulate_crc(ucComMF522Buf, 16, &ucComMF522Buf[16]);

		status = nxp520_communicate_card(PCD_TRANSCEIVE, ucComMF522Buf, 18, ucComMF522Buf, &unLen);
		if ((status != MI_OK) || (unLen != 4) || ((ucComMF522Buf[0] & 0x0F) != 0x0A))
		{
			status = MI_ERR;
		}
	}

	return status;
}

/////////////////////////////////////////////////////////////////////
//功    能：扣款和充值
//参数说明: dd_mode[IN]：命令字
//               0xC0 = 扣款
//               0xC1 = 充值
//          addr[IN]：钱包地址
//          pValue[IN]：4字节增(减)值，低位在前
//返    回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////
char nxp520_value(unsigned char dd_mode, unsigned char addr, unsigned char *pValue)
{
	signed char status;
	unsigned int unLen;
	unsigned char i, ucComMF522Buf[MAXRLEN];

	ucComMF522Buf[0] = dd_mode;
	ucComMF522Buf[1] = addr;
	nxp520_calulate_crc(ucComMF522Buf, 2, &ucComMF522Buf[2]);

	status = nxp520_communicate_card(PCD_TRANSCEIVE, ucComMF522Buf, 4, ucComMF522Buf, &unLen);

	if ((status != MI_OK) || (unLen != 4) || ((ucComMF522Buf[0] & 0x0F) != 0x0A))
	{
		status = MI_ERR;
	}

	if (status == MI_OK)
	{
		// memcpy(ucComMF522Buf, pValue, 4);
		for (i = 0; i < 16; i++)
		{
			ucComMF522Buf[i] = *(pValue + i);
		}
		nxp520_calulate_crc(ucComMF522Buf, 4, &ucComMF522Buf[4]);
		unLen = 0;
		status = nxp520_communicate_card(PCD_TRANSCEIVE, ucComMF522Buf, 6, ucComMF522Buf, &unLen);
		if (status != MI_ERR)
		{
			status = MI_OK;
		}
	}

	if (status == MI_OK)
	{
		ucComMF522Buf[0] = PICC_TRANSFER;
		ucComMF522Buf[1] = addr;
		nxp520_calulate_crc(ucComMF522Buf, 2, &ucComMF522Buf[2]);

		status = nxp520_communicate_card(PCD_TRANSCEIVE, ucComMF522Buf, 4, ucComMF522Buf, &unLen);

		if ((status != MI_OK) || (unLen != 4) || ((ucComMF522Buf[0] & 0x0F) != 0x0A))
		{
			status = MI_ERR;
		}
	}
	return status;
}

/////////////////////////////////////////////////////////////////////
//功    能：备份钱包
//参数说明: sourceaddr[IN]：源地址
//          goaladdr[IN]：目标地址
//返    回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////
signed char nxp520_bak_value(unsigned char sourceaddr, unsigned char goaladdr)
{
	signed char status;
	unsigned int unLen;
	unsigned char ucComMF522Buf[MAXRLEN];

	ucComMF522Buf[0] = PICC_RESTORE;
	ucComMF522Buf[1] = sourceaddr;
	nxp520_calulate_crc(ucComMF522Buf, 2, &ucComMF522Buf[2]);

	status = nxp520_communicate_card(PCD_TRANSCEIVE, ucComMF522Buf, 4, ucComMF522Buf, &unLen);

	if ((status != MI_OK) || (unLen != 4) || ((ucComMF522Buf[0] & 0x0F) != 0x0A))
	{
		status = MI_ERR;
	}

	if (status == MI_OK)
	{
		ucComMF522Buf[0] = 0;
		ucComMF522Buf[1] = 0;
		ucComMF522Buf[2] = 0;
		ucComMF522Buf[3] = 0;
		nxp520_calulate_crc(ucComMF522Buf, 4, &ucComMF522Buf[4]);

		status = nxp520_communicate_card(PCD_TRANSCEIVE, ucComMF522Buf, 6, ucComMF522Buf, &unLen);
		if (status != MI_ERR)
		{
			status = MI_OK;
		}
	}

	if (status != MI_OK)
	{
		return MI_ERR;
	}

	ucComMF522Buf[0] = PICC_TRANSFER;
	ucComMF522Buf[1] = goaladdr;

	nxp520_calulate_crc(ucComMF522Buf, 2, &ucComMF522Buf[2]);

	status = nxp520_communicate_card(PCD_TRANSCEIVE, ucComMF522Buf, 4, ucComMF522Buf, &unLen);

	if ((status != MI_OK) || (unLen != 4) || ((ucComMF522Buf[0] & 0x0F) != 0x0A))
	{
		status = MI_ERR;
	}

	return status;
}

/////////////////////////////////////////////////////////////////////
//功    能：命令卡片进入休眠状态
//返    回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////
char Nxp520_Halt(void)
{
	signed char status;
	unsigned int unLen;
	unsigned char ucComMF522Buf[MAXRLEN];

	ucComMF522Buf[0] = PICC_HALT;
	ucComMF522Buf[1] = 0;
	nxp520_calulate_crc(ucComMF522Buf, 2, &ucComMF522Buf[2]);

	status = nxp520_communicate_card(PCD_TRANSCEIVE, ucComMF522Buf, 4, ucComMF522Buf, &unLen);

	return status;
}

//以上为标准接口
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//低功耗寻卡   周期：520ms cv520工作时间：2.150ms 天线寻卡时间：920us

/////////////////////////////////////////////////////////////////////
//功    能：自定义寻卡    开天线时间没那么块
//参数说明: req_code[IN]:寻卡方式
//                0x52 = 寻感应区内所有符合14443A标准的卡
//                0x26 = 寻未进入休眠状态的卡
//          pTagType[OUT]：卡片类型代码
//                0x4400 = Mifare_UltraLight
//                0x0400 = Mifare_One(S50)
//                0x0200 = Mifare_One(S70)
//                0x0800 = Mifare_Pro(X)
//                0x4403 = Mifare_DESFire
//返    回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////
uint8_t test;
signed char lowpower_communicate_card(unsigned char Command,
									  unsigned char *pInData,
									  unsigned char InLenByte,
									  unsigned char *pOutData,
									  unsigned int *pOutLenBit)
{
	signed char status = MI_ERR;
	unsigned char irqEn = 0x00;
	unsigned char waitFor = 0x00;
	unsigned char lastBits;
	unsigned char n;
	unsigned int i;

	switch (Command)
	{
	case PCD_AUTHENT:
	{
		irqEn = 0x12;
		waitFor = 0x10;
	}
	break;

	case PCD_TRANSCEIVE:
	{
		irqEn = 0x77;
		waitFor = 0x30;
	}
	break;

	default:
		break;
	}

	Nxp520_Write_Reg(ComIEnReg, irqEn | 0x80); //配置中断输出电平，允许一些中断
	cls_reg_mask(ComIrqReg, 0x80);
	Nxp520_Write_Reg(CommandReg, PCD_IDLE);
	Set_Reg_Mask(FIFOLevelReg, 0x80);

	//    Set_Reg_Mask(TxControlReg,ANT_CONFIG);   //打开天线脚驱动     低功耗设计
	//    System_DelayUs(50);  //前面已经开启了天线 Leo

	for (i = 0; i < InLenByte; i++)
	{
		Nxp520_Write_Reg(FIFODataReg, pInData[i]);
	}
	Nxp520_Write_Reg(CommandReg, Command);

	if (Command == PCD_TRANSCEIVE)
		Set_Reg_Mask(BitFramingReg, 0x80);

	i = 100; //Get_Waitcmd_Loop();//根据时钟频率调整，n = 600操作M1卡最大等待时间25ms
	do
	{
		n = Nxp520_Read_Reg(ComIrqReg);
		i--;

		//			if(gSysFlag.bKeyboardFlag == 1)		// 按键退出
		//			{
		//				break;
		//			}
	} while ((i != 0) && !(n & 0x01) && !(n & waitFor));

	cls_reg_mask(BitFramingReg, 0x80);

	if (i != 0) //发送完成
	{
		status = Nxp520_Read_Reg(ErrorReg);
		Set_Reg_Mask(ErrorReg, 0x00);
		// test = Nxp520_Read_Reg(FIFOLevelReg);
		if (!(Nxp520_Read_Reg(ErrorReg) & 0x1B))
		{
			status = MI_OK;
			if (n & irqEn & 0x01)
				status = MI_NOTAGERR;

			if (Command == PCD_TRANSCEIVE)
			{
				n = Nxp520_Read_Reg(FIFOLevelReg);
				lastBits = Nxp520_Read_Reg(ControlReg) & 0x07;
				if (lastBits)
					*pOutLenBit = (n - 1) * 8 + lastBits;
				else
					*pOutLenBit = n * 8;

				if (n == 0)
					n = 1;
				if (n > MAXRLEN)
					n = MAXRLEN;
				for (i = 0; i < n; i++)
				{
					pOutData[i] = Nxp520_Read_Reg(FIFODataReg);
				}
			}
		}
		else
		{
			status = MI_ERR;
		}
	}

	Set_Reg_Mask(ControlReg, 0x80); // stop timer now
	Nxp520_Write_Reg(CommandReg, PCD_IDLE);

	return status;
}

/////////////////////////////////////////////////////////////////////
//功    能：天线在这里面开
//参数说明：Command[IN]:RC522命令字
//          pInData[IN]:通过RC522发送到卡片的数据
//          InLenByte[IN]:发送数据的字节长度
//          pOutData[OUT]:接收到的卡片返回数据
//          *pOutLenBit[OUT]:返回数据的位长度
/////////////////////////////////////////////////////////////////////
signed char Lowpower_Request(unsigned char req_code, unsigned char *pTagType)
{
	volatile signed char status; //不加 volatile 可能会被优化 2012.007.05
	unsigned int unLen;
	unsigned char ucComMF522Buf[MAXRLEN];
	unsigned char *p = pTagType;

	Set_Reg_Mask(TxControlReg, ANT_CONFIG); //打开天线脚驱动

	OSAL_DelayUs(900);
	OSAL_DelayUs(900);
	OSAL_DelayUs(900); //CPU卡必须加这个延时

	cls_reg_mask(Status2Reg, 0x08);		   //清除密文发送
	Nxp520_Write_Reg(BitFramingReg, 0x07); //最后字节只传7位，请求命令是短帧！！！！
										   //Set_Reg_Mask(TxControlReg,ANT_CONFIG);   //打开天线脚驱动      这里先不开，在后面 nxp520_communicate_card中开
	cls_reg_mask(TxModeReg, 0x80);		   //ZG
	cls_reg_mask(RxModeReg, 0x80);		   //ZG
	ucComMF522Buf[0] = req_code;

	status = lowpower_communicate_card(PCD_TRANSCEIVE, ucComMF522Buf, 1, ucComMF522Buf, &unLen); //寻卡

	if ((status == MI_OK) && (unLen == 0x10))
	{
		*p = ucComMF522Buf[1];
		*(p + 1) = ucComMF522Buf[0];
	}
	else
	{
		status = MI_ERR;
	}

	return status;
}

signed char lowpower_cate_card(unsigned char Command,
							   unsigned char *pInData,
							   unsigned char InLenByte,
							   unsigned char *pOutData,
							   unsigned int *pOutLenBit)
{
	unsigned char irqEn = 0x00;
	unsigned char waitFor = 0x00;
	unsigned char n;
	unsigned int i;

	switch (Command)
	{
	case PCD_AUTHENT:
	{
		irqEn = 0x12;
		waitFor = 0x10;
	}
	break;

	case PCD_TRANSCEIVE:
	{
		irqEn = 0x77;
		waitFor = 0x30;
	}
	break;

	default:
		break;
	}
	Nxp520_Write_Reg(ComIEnReg, irqEn | 0x80); //配置中断输出电平，允许一些中断
	cls_reg_mask(ComIrqReg, 0x80);
	Nxp520_Write_Reg(CommandReg, PCD_IDLE);
	Set_Reg_Mask(FIFOLevelReg, 0x80);

	for (i = 0; i < InLenByte; i++)
	{
		Nxp520_Write_Reg(FIFODataReg, pInData[i]);
	}
	Nxp520_Write_Reg(CommandReg, Command);

	if (Command == PCD_TRANSCEIVE)
		Set_Reg_Mask(BitFramingReg, 0x80);

	i = Get_Waitcmd_Loop(); //根据时钟频率调整，n = 600操作M1卡最大等待时间25ms
	do
	{
		n = Nxp520_Read_Reg(ComIrqReg);
		if (n == 0X64)
			break;
		i--;
	} while ((i != 0) && !(n & 0x01) && !(n & waitFor));
	Nxp520_Antenna_Off();
	return n;
}

// 使用单天线寻卡: 寻到卡返回1
signed char Lowpower_ReadCardrequest(void)
{
	signed char status = 0;
	unsigned int unLen;
	unsigned char ucComMF522Buf[MAXRLEN];

	Nxp520_Portinit();
	Nxp520_Reset();

	Set_Reg_Mask(TxControlReg, ANT_TX1); // 打开天线脚驱动: 单天线驱动, 减低功耗

	cls_reg_mask(Status2Reg, 0x08);		   //清除密文发送
	Nxp520_Write_Reg(BitFramingReg, 0x07); //最后字节只传7位，请求命令是短帧！！！！
	ucComMF522Buf[0] = PICC_REQALL;
	status = lowpower_cate_card(PCD_TRANSCEIVE, ucComMF522Buf, 1, ucComMF522Buf, &unLen); //寻卡

	// status==0x64表示寻到卡
	if (status == 0x64)
		status = 1;
	else
		status = 0;

	return status;
}

// -----------------------------------------------------------------------------------------------
//读卡任务
void Get_CardNum(uint8_t *cardbuf)
{
	uint8_t ok_flag;

	ok_flag = UL_PcdAnticoll(cardbuf); //Nxp520_Anticoll(cardbuf);
	if (ok_flag == MI_OK)			   //防冲撞 读卡
	{
		MF_NRST_L; //
		cardbuf[10] = cardbuf[0] ^ cardbuf[1] ^ cardbuf[2] ^ cardbuf[3] ^ cardbuf[4] ^ cardbuf[5] ^ cardbuf[6] ^ cardbuf[7] ^ cardbuf[8] ^ cardbuf[9];
		//gSysFlag.bReadCardFlag = 1;
		//FeedIWDG();
	}
}

// 读卡 1ms
void Nxp520_ReadCard(void)
{
	//	uint8_t type[2],i;
	//
	////	ReadCard_Init();
	//	Set_Waitcmd_Loop(80);
	//	if(Lowpower_Request(PICC_REQIDL,type) == MI_OK) // 寻卡
	//	{
	//		for(i=0;i<CARD_DATA_LEN;i++)
	//		{
	//			gSysData.cardnumbuf[i] = 0xFF;
	//		}
	//		Get_CardNum( gSysData.cardnumbuf );//获取卡号
	//	}

	//	Nxp520_Antenna_Off();
}

// ------------------------------------------------ AD采样方式寻卡 ----------------------------------------------------------------
//void Nxp520_FindCard( void )
//{
//	// 为了降低功耗, 采用AD采样模式.
//	if( gSysData.nSleepTimer == 0 )
//	{
//	//  AD采样模式寻卡
//	// 实测多次, 前后两次的差值90%都小于5,99%小于20
//		if( ReadCard_AdCampare() > 5 )
//		{
//			if( Lowpower_ReadCardrequest() != 0 )		// 单天线寻卡  (GSD添加，AD误唤醒后再加入低功耗寻卡，降低功耗）
//			{
//				Nxp520_ReadCard();										// 4是寻卡次数
//				m_CardAdVar.nAdTimer = 1;
//			  m_CardAdVar.nErrWakeNum++;								// 误唤醒计数器
//			}
//		}
//	}
//	else
//		Nxp520_ReadCard();
//	// 记录当前的timer, 用于判断休眠之后第一次AD采样
//	m_CardAdVar.nAdTimer = gSysData.nSleepTimer;
//}
//#endif

//// 仅仅寻卡: 语音中用于寻卡
//uint8_t Nxp520_SearchCard( void )
//{
//	uint8_t ret = 0;
//  uint8_t type[2];
//
//	ReadCard_Init();
//	Set_Waitcmd_Loop(80);
//	if(Lowpower_Request(PICC_REQIDL,type) == MI_OK)
//	{
//		 ret = 1;
//	}
//
//	Nxp520_Antenna_Off();
//
//	return ret;
//}
/////////////////////////////////////////////////////////////////////
//功    能：清RC522寄存器位
//参数说明：reg[IN]:寄存器地址
//          mask[IN]:清位值
/////////////////////////////////////////////////////////////////////
void SetBitMask(unsigned char reg, unsigned char mask)
{
	char tmp = 0x0;
	tmp = Nxp520_Read_Reg(reg);
	Nxp520_Write_Reg(reg, tmp | mask); // set bit mask
}
/************************************************************************************************* 
 CV520_PcdAnticoll() : 通过防冲撞得到卡号.
参数:   nLevel 冲撞等级 0 --2
        pID    ID return
返回:   MI_OK / MI_ERR
注意: 如果卡号[0]为0x88, 表示还有后续卡号
**************************************************************************************************/
static int CV520_PcdAnticoll(char nLevel, unsigned char *pID)
{
	int status = MI_ERR;
	unsigned char i;
	unsigned int unLen;
	unsigned char ucComBuf[MAXRLEN] = {0};
	unsigned char ucID[MAXRLEN] = {0};
	unsigned char ucAntiColl[] = {PICC_ANTICOLL1, PICC_ANTICOLL2, PICC_ANTICOLL3};

	// 第n级防冲撞. 得到ID的4个字节
	ClearBitMask(Status2Reg, 0x08);
	Nxp520_Write_Reg(BitFramingReg, 0x00);
	ClearBitMask(CollReg, 0x80);

	if (nLevel > 2)
		nLevel = 2;

	ucComBuf[0] = ucAntiColl[nLevel];
	ucComBuf[1] = 0x20;

	status = nxp520_communicate_card(PCD_TRANSCEIVE, ucComBuf, 2, ucID, &unLen);

	if (status != MI_OK)
	{
		return MI_ERR;
	}

	// 根据ISO14333规定, 如果ID[0]为0x88, 表示Cascade tag, 后续3字节为有效ID
	if (ucID[0] == 0x88)
		memcpy(pID, &ucID[1], 3);
	else
		memcpy(pID, &ucID[0], 4);

	// 防冲撞OK, 这里select卡
	SetBitMask(CollReg, 0x80);
	ClearBitMask(Status2Reg, 0x08);
	Nxp520_Write_Reg(BitFramingReg, 0x00);
	ClearBitMask(CollReg, 0x80);

	ucComBuf[0] = ucAntiColl[nLevel];
	ucComBuf[1] = 0x70;

	for (i = 0; i < 5; i++)
	{
		ucComBuf[i + 2] = ucID[i];
	}
	nxp520_calulate_crc(ucComBuf, 7, &ucComBuf[7]);

	status = nxp520_communicate_card(PCD_TRANSCEIVE, ucComBuf, 9, ucComBuf, &unLen);

	if (status == MI_OK && ucID[0] == 0x88)
		status = MI_CT;

	return status;
}

/////////////////////////////////////////////////////////////////////
//  UL_PcdAnticoll() : 得到MIFIRE的卡号
//    4字节卡号一次冲撞, 7字节/10字节需要2/3级冲撞才能得到卡号
/////////////////////////////////////////////////////////////////////
uint8_t UL_PcdAnticoll(unsigned char *pSnr)
{
	char status;
	uint8_t len;

	status = CV520_PcdAnticoll(0, pSnr);
	len = 4;

	if (status == MI_CT)
	{
		status = CV520_PcdAnticoll(1, pSnr + 3);
		len = 7;
	}

	if (status == MI_CT)
	{
		status = CV520_PcdAnticoll(2, pSnr + 6);
		len = 10;
	}
	return (status == MI_OK) ? len : 0;
}
